package com.spark.common.widget

import android.content.Context
import android.content.res.TypedArray
import android.graphics.*
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.text.TextUtils
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.*
import android.widget.FrameLayout
import android.widget.TabWidget
import android.widget.TextView
import com.spark.common.R

/**
 * <><><><><> BageTextView <><><><><><>
 */
class BadgeTextView(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
        android.support.v7.widget.AppCompatTextView(context, attrs, defStyleAttr), BGABadgeable {
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context) : this(context, null, 0)

    override val badge_width: Int
        get() = width
    override val badge_height: Int
        get() = height
    override val badge_parent: ViewParent
        get() = parent
    override val badge_id: Int
        get() = id
    override val badge_context: Context
        get() = context
    override val badge_rootView: View
        get() = rootView
    override val isShowBadge: Boolean
        get() = mBgaBadgeViewHelper.isShowBadge
    override val badgeViewHelper: BGABadgeViewHelper
        get() = mBgaBadgeViewHelper

    private val mBgaBadgeViewHelper: BGABadgeViewHelper =
            BGABadgeViewHelper(this, context, attrs, BGABadgeViewHelper.BadgeGravity.RightTop)

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return mBgaBadgeViewHelper.onTouchEvent(event)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        mBgaBadgeViewHelper.drawBadge(canvas)
    }

    override fun showCirclePointBadge() {
        mBgaBadgeViewHelper.showCirclePointBadge()
    }

    override fun showTextBadge(badgeText: String) {
        mBgaBadgeViewHelper.showTextBadge(badgeText)
    }

    override fun hiddenBadge() {
        mBgaBadgeViewHelper.hiddenBadge()
    }

    override fun showDrawableBadge(bitmap: Bitmap) {
        mBgaBadgeViewHelper.showDrawable(bitmap)
    }

    override fun callSuperOnTouchEvent(event: MotionEvent): Boolean {
        return super.onTouchEvent(event)
    }
}

/**
 * <><><><><><> BageView <><><><><><>
 */
class BadgeView(context: Context, attrs: AttributeSet? = null, defStyle: Int = android.R.attr.textViewStyle) :
        android.support.v7.widget.AppCompatTextView(context, attrs, defStyle) {

    /**
     * @return Returns true if view is hidden on badge value 0 or null;
     */
    /**
     * @param hideOnNull the hideOnNull to set
     */
    var isHideOnNull = true
        set(hideOnNull) {
            field = hideOnNull
            text = text
        }

    val badgeCount: Int?
        get() {
            if (text == null) {
                return null
            }

            val text = text.toString()
            return try {
                Integer.parseInt(text)
            } catch (e: NumberFormatException) {
                null
            }

        }

    var badgeGravity: Int
        get() {
            val params = layoutParams as FrameLayout.LayoutParams
            return params.gravity
        }
        set(gravity) {
            val params = layoutParams as FrameLayout.LayoutParams
            params.gravity = gravity
            layoutParams = params
        }

    val badgeMargin: IntArray
        get() {
            val params = layoutParams as FrameLayout.LayoutParams
            return intArrayOf(params.leftMargin, params.topMargin, params.rightMargin, params.bottomMargin)
        }

    init {

        init()
    }

    private fun init() {
        if (layoutParams !is FrameLayout.LayoutParams) {
            val layoutParams = FrameLayout.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    Gravity.RIGHT or Gravity.TOP)
            setLayoutParams(layoutParams)
        }

        // set default font
        setTextColor(Color.WHITE)
        typeface = Typeface.DEFAULT_BOLD
        setTextSize(TypedValue.COMPLEX_UNIT_SP, 8f)
        // set default background
        setBackground(9, Color.parseColor("#d3321b"))

        gravity = Gravity.CENTER

        // default values
        isHideOnNull = true
        setBadgeCount(0)
    }

    fun setBackground(dipRadius: Int, badgeColor: Int) {
        val radius = dip2Px(dipRadius.toFloat())
        val radiusArray = floatArrayOf(radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat())

        val roundRect = RoundRectShape(radiusArray, null, null)
        val bgDrawable = ShapeDrawable(roundRect)
        bgDrawable.paint.color = badgeColor
        background = bgDrawable
    }

    /**
     * (non-Javadoc)
     *
     * @see android.widget.TextView#setText(java.lang.CharSequence, android.widget.TextView.BufferType)
     */
    override fun setText(text: CharSequence?, type: TextView.BufferType) {
        visibility = if (isHideOnNull && (text == null || text.toString().equals("0", ignoreCase = true))) {
            View.GONE
        } else {
            View.VISIBLE
        }
        super.setText(text, type)
    }

    fun setBadgeCount(count: Int) {
        text = count.toString()
    }

    fun setBadgeMargin(dipMargin: Int) {
        setBadgeMargin(dipMargin, dipMargin, dipMargin, dipMargin)
    }

    fun setBadgeMargin(leftDipMargin: Int, topDipMargin: Int, rightDipMargin: Int, bottomDipMargin: Int) {
        val params = layoutParams as FrameLayout.LayoutParams
        params.leftMargin = dip2Px(leftDipMargin.toFloat())
        params.topMargin = dip2Px(topDipMargin.toFloat())
        params.rightMargin = dip2Px(rightDipMargin.toFloat())
        params.bottomMargin = dip2Px(bottomDipMargin.toFloat())
        layoutParams = params
    }

    fun incrementBadgeCount(increment: Int) {
        val count = badgeCount
        if (count == null) {
            setBadgeCount(increment)
        } else {
            setBadgeCount(increment + count)
        }
    }

    fun decrementBadgeCount(decrement: Int) {
        incrementBadgeCount(-decrement)
    }

    /**
     * Attach the BadgeView to the TabWidget
     *
     * @param target the TabWidget to attach the BadgeView
     *
     * @param tabIndex index of the tab
     */
    fun setTargetView(target: TabWidget, tabIndex: Int) {
        val tabView = target.getChildTabViewAt(tabIndex)
        setTargetView(tabView)
    }

    /**
     * Attach the BadgeView to the target view
     *
     * @param target the view to attach the BadgeView
     */
    fun setTargetView(target: View?) {
        if (parent != null) {
            (parent as ViewGroup).removeView(this)
        }

        if (target == null) {
            return
        }

        if (target.parent is FrameLayout) {
            (target.parent as FrameLayout).addView(this)

        } else if (target.parent is ViewGroup) {
            // use a new Framelayout container for adding badge
            val parentContainer = target.parent as ViewGroup
            val groupIndex = parentContainer.indexOfChild(target)
            parentContainer.removeView(target)

            val badgeContainer = FrameLayout(context)
            val parentLayoutParams = target.layoutParams

            badgeContainer.layoutParams = parentLayoutParams
            target.layoutParams = ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)

            parentContainer.addView(badgeContainer, groupIndex, parentLayoutParams)
            badgeContainer.addView(target)

            badgeContainer.addView(this)
        } else if (target.parent == null) {
            Log.e(javaClass.simpleName, "ParentView is needed")
        }

    }

    /**
     * converts dip to px
     */
    private fun dip2Px(dip: Float): Int {
        return (dip * context.resources.displayMetrics.density + 0.5f).toInt()
    }
}

/**
 * <><><><><><> Baggeable <><><><><><>
 */
interface BGABadgeable {

    /**
     * 是否显示徽章
     *
     * @return
     */
    val isShowBadge: Boolean

    val badgeViewHelper: BGABadgeViewHelper

    val badge_width: Int

    val badge_height: Int

    val badge_parent: ViewParent

    val badge_id: Int

    val badge_context: Context

    val badge_rootView: View
    /**
     * 显示圆点徽章
     */
    fun showCirclePointBadge()

    /**
     * 显示文字徽章
     *
     * @param badgeText
     */
    fun showTextBadge(badgeText: String)

    /**
     * 隐藏徽章
     */
    fun hiddenBadge()

    /**
     * 显示图像徽章
     *
     * @param bitmap
     */
    fun showDrawableBadge(bitmap: Bitmap)

    /**
     * 调用父类的onTouchEvent方法
     *
     * @param event
     * @return
     */
    fun callSuperOnTouchEvent(event: MotionEvent): Boolean

    fun postInvalidate()

    fun getGlobalVisibleRect(r: Rect): Boolean
}

/**
 * <><><><><><> BadgeViewHelper <><><><><><>
 */
class BGABadgeViewHelper(badgeable: BadgeTextView, context: Context, attrs: AttributeSet?, defaultBadgeGravity: BadgeGravity) {
    var bitmap: Bitmap? = null
        private set
    private val mBadgeable: BGABadgeable
    private var mBadgePaint: Paint? = null
    /**
     * 徽章背景色
     */
    var badgeBgColor: Int = 0
        private set
    /**
     * 徽章文本的颜色
     */
    var badgeTextColor: Int = 0
        private set
    /**
     * 徽章文本字体大小
     */
    var badgeTextSize: Int = 0
        private set
    /**
     * 徽章背景与宿主控件上下边缘间距离
     */
    private var mBadgeVerticalMargin: Int = 0
    /**
     * 徽章背景与宿主控件左右边缘间距离
     */
    private var mBadgeHorizontalMargin: Int = 0
    /***
     * 徽章文本边缘与徽章背景边缘间的距离
     */
    var badgePadding: Int = 0
        private set
    /**
     * 徽章文本
     */
    var badgeText: String? = null
        private set
    /**
     * 徽章文本所占区域大小
     */
    private var mBadgeNumberRect: Rect? = null
    /**
     * 是否显示Badge
     */
    var isShowBadge: Boolean = false
        private set
    /**
     * 徽章在宿主控件中的位置
     */
    private var mBadgeGravity: BadgeGravity? = null
    /**
     * 整个徽章所占区域
     */
    var badgeRectF: RectF? = null
        private set
    /**
     * 是否可拖动
     */
    private var mDragable: Boolean = false
    /**
     * 拖拽徽章超出轨迹范围后，再次放回到轨迹范围时，是否恢复轨迹
     */
    private var mIsResumeTravel: Boolean = false
    /***
     * 徽章描边宽度
     */
    private var mBadgeBorderWidth: Int = 0
    /***
     * 徽章描边颜色
     */
    private var mBadgeBorderColor: Int = 0
    /**
     * 触发开始拖拽徽章事件的扩展触摸距离
     */
    private var mDragExtra: Int = 0
    /**
     * 整个徽章加上其触发开始拖拽区域所占区域
     */
    private var mBadgeDragExtraRectF: RectF? = null

    /**
     * 是否正在拖动
     */
    private var mIsDraging: Boolean = false
    var isShowDrawable = false
        private set
    private var mShowText: Boolean = false

    val rootView: View
        get() = mBadgeable.badge_rootView

    var isResumeTravel: Boolean
        get() = mIsResumeTravel
        set(isResumeTravel) {
            mIsResumeTravel = isResumeTravel
            mBadgeable.postInvalidate()
        }

    init {
        mBadgeable = badgeable
        initDefaultAttrs(context, defaultBadgeGravity)
        initCustomAttrs(context, attrs)
        afterInitDefaultAndCustomAttrs()
    }

    private fun initDefaultAttrs(context: Context, defaultBadgeGravity: BadgeGravity) {
        mBadgeNumberRect = Rect()
        badgeRectF = RectF()
        badgeBgColor = Color.RED
        badgeTextColor = Color.WHITE
        badgeTextSize = BGABadgeViewUtil.sp2px(context, 10f)

        mBadgePaint = Paint()
        mBadgePaint!!.isAntiAlias = true
        mBadgePaint!!.style = Paint.Style.FILL
        // 设置mBadgeText居中，保证mBadgeText长度为1时，文本也能居中
        mBadgePaint!!.textAlign = Paint.Align.CENTER

        badgePadding = BGABadgeViewUtil.dp2px(context, 4f)
        mBadgeVerticalMargin = BGABadgeViewUtil.dp2px(context, 4f)
        mBadgeHorizontalMargin = BGABadgeViewUtil.dp2px(context, 4f)

        mBadgeGravity = defaultBadgeGravity
        isShowBadge = false

        badgeText = null

        bitmap = null

        mIsDraging = false

        mDragable = false

        mBadgeBorderColor = Color.WHITE

        mDragExtra = BGABadgeViewUtil.dp2px(context, 4f)
        mBadgeDragExtraRectF = RectF()
    }

    private fun initCustomAttrs(context: Context, attrs: AttributeSet?) {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.BGABadgeView)
        val N = typedArray.indexCount
        for (i in 0 until N) {
            initCustomAttr(typedArray.getIndex(i), typedArray)
        }
        typedArray.recycle()
    }

    private fun initCustomAttr(attr: Int, typedArray: TypedArray) {
        when (attr) {
            R.styleable.BGABadgeView_badge_bgColor -> badgeBgColor = typedArray.getColor(attr, badgeBgColor)
            R.styleable.BGABadgeView_badge_textColor -> badgeTextColor = typedArray.getColor(attr, badgeTextColor)
            R.styleable.BGABadgeView_badge_textSize -> badgeTextSize = typedArray.getDimensionPixelSize(attr, badgeTextSize)
            R.styleable.BGABadgeView_badge_verticalMargin -> mBadgeVerticalMargin = typedArray.getDimensionPixelSize(attr, mBadgeVerticalMargin)
            R.styleable.BGABadgeView_badge_horizontalMargin -> mBadgeHorizontalMargin = typedArray.getDimensionPixelSize(attr, mBadgeHorizontalMargin)
            R.styleable.BGABadgeView_badge_padding -> badgePadding = typedArray.getDimensionPixelSize(attr, badgePadding)
            R.styleable.BGABadgeView_badge_gravity -> {
                val ordinal = typedArray.getInt(attr, mBadgeGravity!!.ordinal)
                mBadgeGravity = BadgeGravity.values()[ordinal]
            }
            R.styleable.BGABadgeView_badge_dragable -> mDragable = typedArray.getBoolean(attr, mDragable)
            R.styleable.BGABadgeView_badge_isResumeTravel -> mIsResumeTravel = typedArray.getBoolean(attr, mIsResumeTravel)
            R.styleable.BGABadgeView_badge_borderWidth -> mBadgeBorderWidth = typedArray.getDimensionPixelSize(attr, mBadgeBorderWidth)
            R.styleable.BGABadgeView_badge_borderColor -> mBadgeBorderColor = typedArray.getColor(attr, mBadgeBorderColor)
            R.styleable.BGABadgeView_badge_dragExtra -> mDragExtra = typedArray.getDimensionPixelSize(attr, mDragExtra)
        }
    }

    private fun afterInitDefaultAndCustomAttrs() {
        mBadgePaint!!.textSize = badgeTextSize.toFloat()
    }

    fun setBadgeBgColorInt(badgeBgColor: Int) {
        this.badgeBgColor = badgeBgColor
        mBadgeable.postInvalidate()
    }

    fun setBadgeTextColorInt(badgeTextColor: Int) {
        this.badgeTextColor = badgeTextColor
        mBadgeable.postInvalidate()
    }

    fun setBadgeTextSizeSp(badgetextSize: Int) {
        if (badgetextSize >= 0) {
            badgeTextSize = BGABadgeViewUtil.sp2px(mBadgeable.badge_context, badgetextSize.toFloat())
            mBadgePaint!!.textSize = badgeTextSize.toFloat()
            mBadgeable.postInvalidate()
        }
    }

    fun setBadgeVerticalMarginDp(badgeVerticalMargin: Int) {
        if (badgeVerticalMargin >= 0) {
            mBadgeVerticalMargin = BGABadgeViewUtil.dp2px(mBadgeable.badge_context, badgeVerticalMargin.toFloat())
            mBadgeable.postInvalidate()
        }
    }

    fun setBadgeHorizontalMarginDp(badgeHorizontalMargin: Int) {
        if (badgeHorizontalMargin >= 0) {
            mBadgeHorizontalMargin = BGABadgeViewUtil.dp2px(mBadgeable.badge_context, badgeHorizontalMargin.toFloat())
            mBadgeable.postInvalidate()
        }
    }

    fun setBadgePaddingDp(badgePadding: Int) {
        if (badgePadding >= 0) {
            this.badgePadding = BGABadgeViewUtil.dp2px(mBadgeable.badge_context, badgePadding.toFloat())
            mBadgeable.postInvalidate()
        }
    }

    fun setBadgeGravity(badgeGravity: BadgeGravity?) {
        if (badgeGravity != null) {
            mBadgeGravity = badgeGravity
            mBadgeable.postInvalidate()
        }
    }

    fun setDragable(dragable: Boolean) {
        mDragable = dragable
        mBadgeable.postInvalidate()
    }

    fun setBadgeBorderWidthDp(badgeBorderWidthDp: Int) {
        if (badgeBorderWidthDp >= 0) {
            mBadgeBorderWidth = BGABadgeViewUtil.dp2px(mBadgeable.badge_context, badgeBorderWidthDp.toFloat())
            mBadgeable.postInvalidate()
        }
    }

    fun setBadgeBorderColorInt(badgeBorderColor: Int) {
        mBadgeBorderColor = badgeBorderColor
        mBadgeable.postInvalidate()
    }

    fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                mBadgeDragExtraRectF!!.left = badgeRectF!!.left - mDragExtra
                mBadgeDragExtraRectF!!.top = badgeRectF!!.top - mDragExtra
                mBadgeDragExtraRectF!!.right = badgeRectF!!.right + mDragExtra
                mBadgeDragExtraRectF!!.bottom = badgeRectF!!.bottom + mDragExtra

                if ((mBadgeBorderWidth == 0 || isShowDrawable) && mDragable && isShowBadge && mBadgeDragExtraRectF!!.contains(event.x, event.y)) {
                    mIsDraging = true
                    mBadgeable.badge_parent.requestDisallowInterceptTouchEvent(true)

                    val badgeableRect = Rect()
                    mBadgeable.getGlobalVisibleRect(badgeableRect)

                    mBadgeable.postInvalidate()
                    return true
                }
            }
            MotionEvent.ACTION_MOVE -> if (mIsDraging) {

                return true
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> if (mIsDraging) {
                mIsDraging = false
                return true
            }
            else -> {
            }
        }
        return mBadgeable.callSuperOnTouchEvent(event)
    }

    fun endDragWithDismiss() {
        hiddenBadge()
    }

    fun endDragWithoutDismiss() {
        mBadgeable.postInvalidate()
    }

    fun drawBadge(canvas: Canvas) {
        if (isShowBadge && !mIsDraging) {
            if (isShowDrawable) {
                drawDrawableBadge(canvas)
            } else {
                drawTextBadge(canvas)
            }
        }
    }

    /**
     * 绘制图像徽章
     *
     * @param canvas
     */
    private fun drawDrawableBadge(canvas: Canvas) {
        badgeRectF!!.left = (mBadgeable.badge_width - mBadgeHorizontalMargin - bitmap!!.width).toFloat()
        badgeRectF!!.top = mBadgeVerticalMargin.toFloat()
        when (mBadgeGravity) {
            BadgeGravity.RightTop -> badgeRectF!!.top = mBadgeVerticalMargin.toFloat()
            BadgeGravity.RightCenter -> badgeRectF!!.top = ((mBadgeable.badge_height - bitmap!!.height) / 2).toFloat()
            BadgeGravity.RightBottom -> badgeRectF!!.top = (mBadgeable.badge_height - bitmap!!.height - mBadgeVerticalMargin).toFloat()
            else -> {
            }
        }
        canvas.drawBitmap(bitmap!!, badgeRectF!!.left, badgeRectF!!.top, mBadgePaint)
        badgeRectF!!.right = badgeRectF!!.left + bitmap!!.width
        badgeRectF!!.bottom = badgeRectF!!.top + bitmap!!.height
    }

    /**
     * 绘制文字徽章
     *
     * @param canvas
     */
    private fun drawTextBadge(canvas: Canvas) {
        var badgeText = ""
        if (!TextUtils.isEmpty(this.badgeText)) {
            badgeText = this.badgeText ?: ""
        }
        // 获取文本宽所占宽高
        mBadgePaint!!.getTextBounds(badgeText, 0, badgeText.length, mBadgeNumberRect)
        // 计算徽章背景的宽高
        val badgeHeight = mBadgeNumberRect!!.height() + badgePadding * 2
        val badgeWidth: Int
        // 当mBadgeText的长度为1或0时，计算出来的高度会比宽度大，此时设置宽度等于高度
        if (badgeText.length == 1 || badgeText.length == 0) {
            badgeWidth = badgeHeight
        } else {
            badgeWidth = mBadgeNumberRect!!.width() + badgePadding * 2
        }

        // 计算徽章背景上下的值
        //mBadgeRectF.top = mBadgeVerticalMargin;
        badgeRectF!!.top = 0f
        badgeRectF!!.bottom = (mBadgeable.badge_height - mBadgeVerticalMargin).toFloat()
        when (mBadgeGravity) {
            BadgeGravity.RightTop -> badgeRectF!!.bottom = badgeRectF!!.top + badgeHeight
            BadgeGravity.RightCenter -> {
                badgeRectF!!.top = ((mBadgeable.badge_height - badgeHeight) / 2).toFloat()
                badgeRectF!!.bottom = badgeRectF!!.top + badgeHeight
            }
            BadgeGravity.RightBottom -> badgeRectF!!.top = badgeRectF!!.bottom - badgeHeight
            else -> {
            }
        }

        // 计算徽章背景左右的值
        //mBadgeRectF.ic_arrow_right_blue = mBadgeable.getBadge_width() - mBadgeHorizontalMargin;
        badgeRectF!!.right = mBadgeable.badge_width.toFloat()
        badgeRectF!!.left = badgeRectF!!.right - badgeWidth
        //mBadgeRectF.left = mBadgeRectF.ic_arrow_right_blue;

        if (mBadgeBorderWidth > 0) {
            // 设置徽章边框景色
            mBadgePaint!!.color = mBadgeBorderColor
            // 绘制徽章边框背景
            canvas.drawRoundRect(badgeRectF!!, (badgeHeight / 2).toFloat(), (badgeHeight / 2).toFloat(), mBadgePaint!!)

            // 设置徽章背景色
            mBadgePaint!!.color = badgeBgColor
            // 绘制徽章背景
            canvas.drawRoundRect(RectF(badgeRectF!!.left + mBadgeBorderWidth, badgeRectF!!.top + mBadgeBorderWidth, badgeRectF!!.right - mBadgeBorderWidth, badgeRectF!!.bottom - mBadgeBorderWidth), ((badgeHeight - 2 * mBadgeBorderWidth) / 2).toFloat(), ((badgeHeight - 2 * mBadgeBorderWidth) / 2).toFloat(), mBadgePaint!!)
        } else {
            // 设置徽章背景色
            mBadgePaint!!.color = badgeBgColor
            // 绘制徽章背景
            canvas.drawRoundRect(badgeRectF!!, (badgeHeight / 2).toFloat(), (badgeHeight / 2).toFloat(), mBadgePaint!!)
        }


        if (!TextUtils.isEmpty(this.badgeText)) {
            // 设置徽章文本颜色
            mBadgePaint!!.color = badgeTextColor
            // initDefaultAttrs方法中设置了mBadgeText居中，此处的x为徽章背景的中心点y
            val x = badgeRectF!!.left + badgeWidth / 2
            // 注意：绘制文本时的y是指文本底部，而不是文本的中间
            val y = badgeRectF!!.bottom - badgePadding
            // 绘制徽章文本
            canvas.drawText(badgeText, x, y, mBadgePaint!!)
        }
    }

    private fun drawCirclePoint(canvas: Canvas) {
        var badgeText = ""
        if (!TextUtils.isEmpty(this.badgeText)) {
            badgeText = this.badgeText ?: ""
        }
        // 获取文本宽所占宽高
        mBadgePaint!!.getTextBounds(badgeText, 0, badgeText.length, mBadgeNumberRect)
        // 计算徽章背景的宽高
        val badgeHeight = mBadgeNumberRect!!.height() + badgePadding * 2
        val badgeWidth: Int
        // 当mBadgeText的长度为1或0时，计算出来的高度会比宽度大，此时设置宽度等于高度
        if (badgeText.length == 1 || badgeText.length == 0) {
            badgeWidth = badgeHeight
        } else {
            badgeWidth = mBadgeNumberRect!!.width() + badgePadding * 2
        }

        // 计算徽章背景上下的值
        //mBadgeRectF.top = mBadgeVerticalMargin;
        badgeRectF!!.top = 0f
        badgeRectF!!.bottom = (mBadgeable.badge_height - mBadgeVerticalMargin).toFloat()
        when (mBadgeGravity) {
            BadgeGravity.RightTop -> badgeRectF!!.bottom = badgeRectF!!.top + badgeHeight
            BadgeGravity.RightCenter -> {
                badgeRectF!!.top = ((mBadgeable.badge_height - badgeHeight) / 2).toFloat()
                badgeRectF!!.bottom = badgeRectF!!.top + badgeHeight
            }
            BadgeGravity.RightBottom -> badgeRectF!!.top = badgeRectF!!.bottom - badgeHeight
            else -> {
            }
        }

        // 计算徽章背景左右的值
        //mBadgeRectF.ic_arrow_right_blue = mBadgeable.getBadge_width() - mBadgeHorizontalMargin;
        badgeRectF!!.right = mBadgeable.badge_width.toFloat()
        badgeRectF!!.left = badgeRectF!!.right - badgeWidth
        //mBadgeRectF.left = mBadgeRectF.ic_arrow_right_blue;

        if (mBadgeBorderWidth > 0) {
            // 设置徽章边框景色
            mBadgePaint!!.color = mBadgeBorderColor
            // 绘制徽章边框背景
            canvas.drawRoundRect(badgeRectF!!, (badgeHeight / 2).toFloat(), (badgeHeight / 2).toFloat(), mBadgePaint!!)

            // 设置徽章背景色
            mBadgePaint!!.color = badgeBgColor
            // 绘制徽章背景
            canvas.drawRoundRect(RectF(badgeRectF!!.left + mBadgeBorderWidth, badgeRectF!!.top + mBadgeBorderWidth, badgeRectF!!.right - mBadgeBorderWidth, badgeRectF!!.bottom - mBadgeBorderWidth), ((badgeHeight - 2 * mBadgeBorderWidth) / 2).toFloat(), ((badgeHeight - 2 * mBadgeBorderWidth) / 2).toFloat(), mBadgePaint!!)
        } else {
            // 设置徽章背景色
            mBadgePaint!!.color = badgeBgColor
            // 绘制徽章背景
            canvas.drawRoundRect(badgeRectF!!, (badgeHeight / 2).toFloat(), (badgeHeight / 2).toFloat(), mBadgePaint!!)
        }


        if (!TextUtils.isEmpty(this.badgeText)) {
            // 设置徽章文本颜色
            mBadgePaint!!.color = badgeTextColor
            // initDefaultAttrs方法中设置了mBadgeText居中，此处的x为徽章背景的中心点y
            val x = badgeRectF!!.left + badgeWidth / 2
            // 注意：绘制文本时的y是指文本底部，而不是文本的中间
            val y = badgeRectF!!.bottom - badgePadding
            // 绘制徽章文本
            if (mShowText) {
                canvas.drawText(badgeText, x, y, mBadgePaint!!)
            }
        }
    }

    fun showCirclePointBadge() {
        showCirclePoint("")
    }

    fun showCirclePoint(badgeText: String) {
        isShowDrawable = false
        this.badgeText = badgeText
        isShowBadge = true
        mShowText = false
        mBadgeable.postInvalidate()
    }

    fun showTextBadge(badgeText: String) {
        isShowDrawable = false
        this.badgeText = badgeText
        isShowBadge = true
        mShowText = true
        mBadgeable.postInvalidate()
    }

    fun hiddenBadge() {
        isShowBadge = false
        mBadgeable.postInvalidate()
    }

    fun showDrawable(bitmap: Bitmap) {
        this.bitmap = bitmap
        isShowDrawable = true
        isShowBadge = true
        mBadgeable.postInvalidate()
    }

    enum class BadgeGravity {
        RightTop,
        RightCenter,
        RightBottom
    }
}

/**
 * <><><><><><> BadgeViewUtil <><><><><><>
 */
object BGABadgeViewUtil {

    fun dp2px(context: Context, dpValue: Float): Int {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.resources.displayMetrics).toInt()
    }

    fun sp2px(context: Context, spValue: Float): Int {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, context.resources.displayMetrics).toInt()
    }

    fun getStatusBarHeight(view: View): Int {
        val rectangle = Rect()
        view.rootView.getWindowVisibleDisplayFrame(rectangle)
        return rectangle.top
    }

    fun getDistanceBetween2Points(p0: PointF, p1: PointF): Float {
        return Math.sqrt(Math.pow((p0.y - p1.y).toDouble(), 2.0) + Math.pow((p0.x - p1.x).toDouble(), 2.0)).toFloat()
    }

    fun getMiddlePoint(p1: PointF, p2: PointF): PointF {
        return PointF((p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f)
    }

    fun getPointByPercent(p1: PointF, p2: PointF, percent: Float): PointF {
        return PointF(evaluate(percent, p1.x, p2.x), evaluate(percent, p1.y, p2.y))
    }

    // 从FloatEvaluator中拷贝过来,这样就不用每次都new FloatEvaluator了
    fun evaluate(fraction: Float, startValue: Number, endValue: Number): Float {
        val startFloat = startValue.toFloat()
        return startFloat + fraction * (endValue.toFloat() - startFloat)
    }

    fun getIntersectionPoints(pMiddle: PointF, radius: Float, lineK: Double?): Array<PointF?> {
        val points = arrayOfNulls<PointF>(2)

        val radian: Float
        var xOffset = 0f
        var yOffset = 0f
        if (lineK != null) {
            radian = Math.atan(lineK).toFloat()
            xOffset = (Math.sin(radian.toDouble()) * radius).toFloat()
            yOffset = (Math.cos(radian.toDouble()) * radius).toFloat()
        } else {
            xOffset = radius
            yOffset = 0f
        }
        points[0] = PointF(pMiddle.x + xOffset, pMiddle.y - yOffset)
        points[1] = PointF(pMiddle.x - xOffset, pMiddle.y + yOffset)

        return points
    }
}